package cn.xinfei.xdecision.common.service.component.decisiontree.impl;

import cn.hutool.core.date.DateUtil;
import cn.xinfei.xdecision.common.dao.component.decisiontree.DecisionTreeVersionMapper;
import cn.xinfei.xdecision.common.model.common.PageResult;
import cn.xinfei.xdecision.common.model.common.ResponseEntityDto;
import cn.xinfei.xdecision.common.model.common.requestParam.AssemblyRuleCodeReq;
import cn.xinfei.xdecision.common.model.common.requestParam.StatusParam;
import cn.xinfei.xdecision.common.model.component.decisiontree.DecisionTree;
import cn.xinfei.xdecision.common.model.component.decisiontree.DecisionTreeDetail;
import cn.xinfei.xdecision.common.model.component.decisiontree.DecisionTreeDetailCondition;
import cn.xinfei.xdecision.common.model.component.decisiontree.DecisionTreeVersion;
import cn.xinfei.xdecision.common.model.component.decisiontree.vo.DecisionTreeVersionListVo;
import cn.xinfei.xdecision.common.model.component.decisiontree.vo.DecisionTreeVersionVo;
import cn.xinfei.xdecision.common.model.component.strategyout.StrategyOutput;
import cn.xinfei.xdecision.common.model.login.SessionManager;
import cn.xinfei.xdecision.common.service.common.sso.SSOService;
import cn.xinfei.xdecision.common.service.common.sso.dto.SSOUserInfoReqDto;
import cn.xinfei.xdecision.common.service.common.sso.dto.SSOUserInfoRespDto;
import cn.xinfei.xdecision.common.service.component.ComponentCommonContext;
import cn.xinfei.xdecision.common.service.component.decisiontree.DecisionTreeDetailConditionService;
import cn.xinfei.xdecision.common.service.component.decisiontree.DecisionTreeDetailService;
import cn.xinfei.xdecision.common.service.component.decisiontree.DecisionTreeService;
import cn.xinfei.xdecision.common.service.component.decisiontree.DecisionTreeVersionService;
import cn.xinfei.xdecision.common.service.component.strategyout.StrategyOutputService;
import cn.xinfei.xdecision.common.utils.constant.SysConstant;
import cn.xinfei.xdecision.common.utils.enums.enginex.ComponentStatusEnum;
import cn.xinfei.xdecision.common.utils.enums.enginex.ComponentTypeEnum;
import cn.xinfei.xdecision.common.utils.enums.enginex.ComponentVersionStatusEnum;
import cn.xinfei.xdecision.common.utils.exception.ApiException;
import cn.xinfei.xdecision.common.utils.exception.enums.ErrorCodeEnum;
import cn.xinfei.xdecision.common.utils.util.BeanUtilsPlus;
import cn.xinfei.xdecision.common.utils.util.strategyx.CustomValueUtils;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageInfo;
import com.github.pagehelper.page.PageMethod;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

@Service("decisionTreeVersionService")
@Slf4j
public class DecisionTreeVersionServiceImpl extends ServiceImpl<DecisionTreeVersionMapper, DecisionTreeVersion> implements DecisionTreeVersionService {

    @Resource
    private DecisionTreeVersionMapper versionMapper;

    @Resource
    private DecisionTreeDetailService detailService;

    @Resource
    private DecisionTreeDetailConditionService conditionService;

    @Resource
    private StrategyOutputService outputService;

    @Resource
    private DecisionTreeService decisionTreeService;

    @Resource
    private TransactionTemplate transactionTemplate;

    @Resource
    private SSOService ssoService;

    @Resource
    private DecisionTreeVersionServiceImpl decisionTreeVersionService;

    @Override
    public DecisionTreeVersionVo queryById(Long id) {
        DecisionTreeVersion version = this.getById(id);
        if (version == null) {
            return null;
        }
        DecisionTreeVersionVo decisionTreeVersionVo = new DecisionTreeVersionVo();
        BeanUtils.copyProperties(version, decisionTreeVersionVo);
        decisionTreeVersionVo.setVersionNoDesc("V" + decisionTreeVersionVo.getVersionNo());
        decisionTreeVersionVo.setStatusDesc(Objects.requireNonNull(ComponentVersionStatusEnum.get(version.getStatus())).getName());
        //查询详情
        List<DecisionTreeDetail> detailList = detailService.queryByVersionId(id);
        decisionTreeVersionVo.setDetailList(detailList);
        //查询策略输出
        List<StrategyOutput> strategyOutputs = outputService.queryByTactics(new StrategyOutput(id, ComponentTypeEnum.DECISION_TREE.getType()));
        decisionTreeVersionVo.setStrategyOutputList(strategyOutputs);
        return decisionTreeVersionVo;
    }

    @Override
    public List<DecisionTreeVersionVo> queryVersionListByDecisionTreeId(Long decisionTreeCode) {
        LambdaQueryWrapper<DecisionTreeVersion> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DecisionTreeVersion::getDecisionTreeCode, decisionTreeCode);
        queryWrapper.eq(DecisionTreeVersion::getStatus, 1);
        queryWrapper.orderByDesc(DecisionTreeVersion::getId);
        List<DecisionTreeVersion> ruleVersionList = versionMapper.selectList(queryWrapper);
        List<DecisionTreeVersionVo> DecisionTreeVersionVoList = new ArrayList<>();
        for (DecisionTreeVersion ruleVersion : ruleVersionList) {
            DecisionTreeVersionVo versionVo = new DecisionTreeVersionVo();
            BeanUtils.copyProperties(ruleVersion, versionVo);
            DecisionTreeVersionVoList.add(versionVo);
        }
        return DecisionTreeVersionVoList;
    }

    @Override
    public List<DecisionTreeVersionVo> queryVersionByTreeCodes(String decisionTreeCode, Long versionNo) {
        if (StringUtils.isEmpty(decisionTreeCode)) {
            return new ArrayList<>();
        }
        LambdaQueryWrapper<DecisionTreeVersion> lbd = new LambdaQueryWrapper<DecisionTreeVersion>()
                .in(DecisionTreeVersion::getDecisionTreeCode, decisionTreeCode);
        lbd.eq(DecisionTreeVersion::getVersionNo, versionNo);
        List<DecisionTreeVersion> versions = this.list(lbd);
        if (CollectionUtils.isEmpty(versions)) {
            return new ArrayList<>();
        }
        //校验版本状态，新建最多只会存在一个
        Map<String, Long> collect = versions.stream()
                .filter(x -> Objects.equals(x.getStatus(), ComponentVersionStatusEnum.NEW.getStatus()))
                .collect(Collectors.groupingBy(x -> x.getDecisionTreeCode() + "_" + x.getStatus(), Collectors.counting()));
        StringBuilder stringBuilder = new StringBuilder();
        collect.forEach((key, value) -> {
            if (value > 1) {
                stringBuilder.append(key, 0, key.lastIndexOf("_")).append(";");
            }
        });
        if (stringBuilder.length() > 0) {
            throw new ApiException(
                    ErrorCodeEnum.ERROR_DECISION_VERSION.getCode()
                    , ErrorCodeEnum.ERROR_DECISION_VERSION.getMessage() + "决策树编号：" + stringBuilder);
        }
        return BeanUtilsPlus.copyElements(versions, DecisionTreeVersionVo::new);
    }

    @Override
    public List<DecisionTreeVersionVo> queryVersionByTreeCodes(List<String> decisionTreeCodes, Integer status) {
        if (CollectionUtils.isEmpty(decisionTreeCodes)) {
            return new ArrayList<>();
        }
        LambdaQueryWrapper<DecisionTreeVersion> lbd = new LambdaQueryWrapper<DecisionTreeVersion>()
                .in(DecisionTreeVersion::getDecisionTreeCode, decisionTreeCodes);
        if (Objects.nonNull(status)) {
            lbd.eq(DecisionTreeVersion::getStatus, status);
        }
        List<DecisionTreeVersion> versions = this.list(lbd);
        if (CollectionUtils.isEmpty(versions)) {
            return new ArrayList<>();
        }
        //校验版本状态，新建最多只会存在一个
        Map<String, Long> collect = versions.stream()
                .filter(x -> Objects.equals(x.getStatus(), ComponentVersionStatusEnum.NEW.getStatus()))
                .collect(Collectors.groupingBy(x -> x.getDecisionTreeCode() + "_" + x.getStatus(), Collectors.counting()));
        StringBuilder stringBuilder = new StringBuilder();
        collect.forEach((key, value) -> {
            if (value > 1) {
                stringBuilder.append(key, 0, key.lastIndexOf("_")).append(";");
            }
        });
        if (stringBuilder.length() > 0) {
            throw new ApiException(
                    ErrorCodeEnum.ERROR_DECISION_VERSION.getCode()
                    , ErrorCodeEnum.ERROR_DECISION_VERSION.getMessage() + "决策树编号：" + stringBuilder);
        }
        return BeanUtilsPlus.copyElements(versions, DecisionTreeVersionVo::new);
    }

    @Override
    public List<String> queryFieldEnByVersionId(Long versionId) {
        Set<String> fieldEns = new HashSet<>();
        LambdaQueryWrapper<DecisionTreeDetail> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DecisionTreeDetail::getVersionId, versionId);
        List<DecisionTreeDetail> list = detailService.list(queryWrapper);
        Set<Long> detailIds = new HashSet<>();
        for (DecisionTreeDetail detail : list) {
            if (detail.getFieldCode().contains(".") && !detail.getFieldCode().startsWith("%")) {
                fieldEns.add(detail.getFieldCode().split("\\.")[0]);
            } else {
                fieldEns.add(detail.getFieldCode());
            }
//            fieldEns.add(detail.getFieldEn());
//            detailIds.add(detail.getId());
        }
        LambdaQueryWrapper<DecisionTreeDetailCondition> conditionWrapper = new LambdaQueryWrapper<>();
        if (detailIds.size() > 0) {
            conditionWrapper.in(DecisionTreeDetailCondition::getDetailId, detailIds);
            List<DecisionTreeDetailCondition> conditionList = conditionService.list(conditionWrapper);
            for (DecisionTreeDetailCondition condition : conditionList) {
                if (condition.getValueType() == null || condition.getValueType() == 1) {
                    continue;
                }
                if (condition.getValueType() == 2) {
//                    fieldEns.add(condition.getFieldValue());
                    String fieldValue = condition.getValue();
                    if (fieldValue.contains(".") && !fieldValue.startsWith("%")) {
                        fieldEns.add(fieldValue.split("\\.")[0]);
                    } else {
                        fieldEns.add(fieldValue);
                    }
                } else if (condition.getValueType() == 3) {
                    fieldEns.addAll(CustomValueUtils.getFieldEnSet(condition.getValue()));
                }
            }
        }
        return new ArrayList<>(fieldEns);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addVersionList(List<DecisionTreeVersionVo> versionList) {
        for (DecisionTreeVersionVo versionVo : versionList) {
            if (Boolean.FALSE.equals(saveOrUpdateVersion(versionVo))) {
                throw new ApiException(ErrorCodeEnum.DECISION_SAVE_ERROR.getCode(),
                        ErrorCodeEnum.DECISION_SAVE_ERROR.getMessage() + ",版本号信息==》" + JSON.toJSONString(versionVo));
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public boolean addVersion(DecisionTreeVersionVo version) {
        //插入子表（detail表）数据
        return versionMapper.insert(version) > 0 &&
                detailService.addDecisionTreeDetailList(version.getId(), version.getDetailList()) &&
                outputService.insertTacticsOutput(version.getId(), version.getStrategyOutputList());
    }

    @Override
    @Transactional
    public boolean updateVersion(DecisionTreeVersionVo version) {
        //修改版本主表
        versionMapper.updateById(version);
        //修改条件表
        detailService.updateByVersionId(version.getId(), version.getDetailList());

        outputService.updateTacticsOutput(version.getId(), version.getStrategyOutputList(), ComponentTypeEnum.DECISION_TREE.getType());
        return true;
    }

    @Override
    @Transactional
    public boolean updateStatus(StatusParam statusParam) {
        LambdaQueryWrapper<DecisionTreeVersion> updateWrapper = new LambdaQueryWrapper<>();
        updateWrapper.in(DecisionTreeVersion::getId, statusParam.getIds());
//        updateWrapper.eq(DecisionTreeVersion::getDecisionTreeId, statusParam.getStrategyId());
        DecisionTreeVersion ruleVersion = new DecisionTreeVersion();
        ruleVersion.setStatus(statusParam.getStatus());
        boolean update = this.update(ruleVersion, updateWrapper);
        return update;
    }


    @Override
    public List<String> queryFieldEnByVersionIdRunner(Long versionId) {
        Set<String> fieldEns = new HashSet<>();

        List<DecisionTreeDetail> list = null;

        LambdaQueryWrapper<DecisionTreeDetail> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DecisionTreeDetail::getVersionId, versionId);
        list = detailService.list(queryWrapper);
        if (list != null && !list.isEmpty()) {
            Set<Long> detailIds = new HashSet<>();
            for (DecisionTreeDetail detail : list) {
                fieldEns.add(detail.getFieldCode());
                detailIds.add(detail.getId());
            }
            fieldEns.addAll(conditionService.queryFieldEnByDetailIds(detailIds));
        }
        return new ArrayList<>(fieldEns);
    }

    @Override
    public void lockDecisionTree(Long versionId) {
        DecisionTreeVersion decisionTreeVersion = this.getById(versionId);
        if (!Objects.equals(decisionTreeVersion.getStatus(), ComponentVersionStatusEnum.NEW.getStatus())) {
            throw new ApiException(ErrorCodeEnum.DECISION_LOCK_ERROR_001);
        }
        DecisionTree decisionTree = decisionTreeService.getOne(new LambdaQueryWrapper<DecisionTree>()
                .eq(DecisionTree::getCode, decisionTreeVersion.getDecisionTreeCode()));
        if (Objects.isNull(decisionTree)) {
            throw new ApiException(ErrorCodeEnum.PARAMS_EXCEPTION);
        }

        //校验当前版本信息完整性
        Set<String> emptyFieldSet = new HashSet<>();
        DecisionTreeVersionVo decisionTreeVersionVo = queryById(versionId);
        ComponentCommonContext.checkParamNotEmpty(decisionTreeVersionVo, emptyFieldSet);
        //自定义校验
        if (!CollectionUtils.isEmpty(decisionTreeVersionVo.getDetailList())) {
            decisionTreeVersionVo.getDetailList().forEach(x -> x.checkDetail(emptyFieldSet));
        }
        if (!CollectionUtils.isEmpty(emptyFieldSet)) {
            log.info(ErrorCodeEnum.INCOMPLETE_COMPONENT_INFORMATION.getMessage() + ",versionId:{},emptyFieldSet:{}",
                    versionId, JSON.toJSONString(emptyFieldSet));
            throw new ApiException(ErrorCodeEnum.INCOMPLETE_COMPONENT_INFORMATION);
        }

        decisionTreeVersion.setStatus(ComponentVersionStatusEnum.ENABLE.getStatus());
        Boolean execute = transactionTemplate.execute(status -> {
            try {
                decisionTree.setStatus(ComponentStatusEnum.ENABLE.getStatus());
                return this.updateById(decisionTreeVersion) && decisionTreeService.updateById(decisionTree);
            } catch (Exception e) {
                status.setRollbackOnly();
                log.error("决策树锁定规则失败，版本id==>{}", versionId, e);
                throw new ApiException(ErrorCodeEnum.DECISION_LOCK_ERROR_002);
            }
        });
        if (Boolean.FALSE.equals(execute)) {
            throw new ApiException(ErrorCodeEnum.DECISION_LOCK_ERROR_002);
        }
    }

    @Override
    public ResponseEntityDto<PageResult<List<DecisionTreeVersionListVo>, DecisionTreeVersion>> listByDecisionTreeCode(AssemblyRuleCodeReq req) {
        PageMethod.startPage(req.getPageNo(), req.getPageSize());
        List<DecisionTreeVersion> list = this.list(new LambdaQueryWrapper<DecisionTreeVersion>()
                .eq(DecisionTreeVersion::getDecisionTreeCode, req.getRuleCode()));
        List<DecisionTreeVersionListVo> decisionTreeVersionListVos =
                BeanUtilsPlus.copyElements(list, DecisionTreeVersionListVo::new);
        if (CollectionUtils.isEmpty(list)) {
            return PageResult.success(new ArrayList<>(), new PageInfo<>());
        }
        SSOUserInfoReqDto ssoUserInfoReqDto = new SSOUserInfoReqDto();
        Set<Long> userIds = new HashSet<>();
        decisionTreeVersionListVos.forEach(x -> {
            userIds.add(x.getCreateUserId());
            userIds.add(x.getUpdateUserId());
        });
        ssoUserInfoReqDto.setId(new ArrayList<>(userIds));
        Map<Long, String> sysMap = ssoService.getUserInfos(ssoUserInfoReqDto).stream()
                .collect(Collectors.toMap(SSOUserInfoRespDto::getId, SSOUserInfoRespDto::getName));
        decisionTreeVersionListVos.forEach(x ->
                x.setStatusDesc(Objects.requireNonNull(ComponentVersionStatusEnum.get(x.getStatus())).getName())
                        .setCreateUserName(sysMap.getOrDefault(x.getCreateUserId(), SysConstant.EMPTY_STRING))
                        .setUpdateUserName(sysMap.getOrDefault(x.getUpdateUserId(), SysConstant.EMPTY_STRING))
                        .setVersionNoDesc("V" + x.getVersionNo()));
        return PageResult.success(decisionTreeVersionListVos, new PageInfo<>(list));
    }

    @Override
    public Long checkAndAddVersion(DecisionTreeVersionVo version) {
        if (StringUtils.isEmpty(version.getDecisionTreeCode())) {
            throw new ApiException(ErrorCodeEnum.DECISION_CODE_CAN_NOT_NULL.getCode(),
                    ErrorCodeEnum.DECISION_CODE_CAN_NOT_NULL.getMessage());
        }
        version.setStatus(ComponentVersionStatusEnum.NEW.getStatus());
        List<DecisionTreeVersionVo> decisionTreeVersionVos =
                queryVersionByTreeCodes(Collections.singletonList(version.getDecisionTreeCode()), null);
        version.setOrganId(SessionManager.getLoginAccount().getOrganId());
        //如果是初始
        if (CollectionUtils.isEmpty(decisionTreeVersionVos)) {
            version.setId(null);
            version.setVersionNo(SysConstant.ZERO);
            //装配节点类型
            version.recursionNodeType();
        } else {
            DecisionTreeVersionVo newVersion = decisionTreeVersionVos.stream()
                    .filter(x -> Objects.equals(x.getStatus(), ComponentVersionStatusEnum.NEW.getStatus()))
                    .findFirst().orElse(null);
            //如果不存在新建，版本号为最大版本号+1
            if (Objects.isNull(newVersion)) {
                DecisionTreeVersionVo maxVersion = decisionTreeVersionVos.stream()
                        .max(Comparator.comparing(DecisionTreeVersionVo::getVersionNo)).orElse(null);
                if (Objects.isNull(maxVersion)) {
                    throw new ApiException(ErrorCodeEnum.ERROR_DECISION_VERSION.getCode(), ErrorCodeEnum.ERROR_DECISION_VERSION.getMessage());
                }
                version.setVersionNo(maxVersion.getVersionNo() + 1);
                version.setDescription("新建版本");
                //版本及详情id置空
                version.recurrenceSetIdIsNull();
            } else {
                //如果存在新建的，则覆盖版本的全部信息
                version.setId(newVersion.getId());
            }
        }
        Boolean execute = transactionTemplate.execute(status -> {
            try {
                //更新规则的更新人，更新时间
                DecisionTree decisionTree = new DecisionTree();
                decisionTree.setUpdatedTime(DateUtil.now());
                decisionTree.setUpdateUserId(SessionManager.getLoginUserId());
                boolean update = decisionTreeService.update(decisionTree,
                        new LambdaQueryWrapper<DecisionTree>().eq(DecisionTree::getCode, version.getDecisionTreeCode()));
                return update && decisionTreeVersionService.saveOrUpdateVersion(version);
            } catch (Exception e) {
                status.setRollbackOnly();
                log.error("决策树新建版本失败，版本==》{}", JSON.toJSONString(version), e);
                throw new ApiException(ErrorCodeEnum.DECISION_VERSION_NEW_ERROR);
            }
        });
        if (Boolean.FALSE.equals(execute)) {
            throw new ApiException(ErrorCodeEnum.DECISION_VERSION_NEW_ERROR);
        }
        return version.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean saveOrUpdateVersion(DecisionTreeVersionVo version) {
        DecisionTreeVersion decisionTreeVersion = BeanUtilsPlus.copyProperties(version, DecisionTreeVersion::new);
        if (Objects.isNull(decisionTreeVersion)) {
            return Boolean.TRUE;
        }
        if (Objects.isNull(decisionTreeVersion.getId())) {
            return addVersion(version);
        }
        return updateVersion(version);
    }
}
